/**
 * @copyright: Copyright (c) hotel.jd.com All Rights Reserved
 * @file: ExpediaHttpServiceImpl.java project: trip-hotel-resource
 * @creator: zhangwansheng
 * @date: 2019/1/4
 */
package service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import common.HttpResponseInfo;
import constant.Constant;
import expedia.HotelChain;
import expedia.HotelInfoResponse;
import expedia.HotelInformationResponseExpedia;
import expedia.chain.ChainInfoResponse;
import expedia.region.RegionInfo;
import expedia.region.RegionInfoResponse;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.ExpediaSignatureUtil;
import util.HttpClientUtil;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;


/**
 * expedia接口调用
 *
 * @author: zhangwansheng
 * @createdate: 2019-01-04 17:12
 * @lastdate:
 */
//@Service("expediaHttpService")
public class ExpediaHttpServiceImpl implements ExpediaHttpService {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * expedia酒店地址
     */
    private static final String EXPEDIA_HOTEL_URL = "https://test.ean.com/2.3/properties/content";
    private static final String EXPEDIA_REGION_URL = "https://test.ean.com/2.3/regions";
    private static final String EXPEDIA_CHAIN_URL = "https://test.ean.com/2.3/chains";
    private static final String API_KEY = "1v8sptbnok1d0rit8hv24k97ia"; //2mkq3o7dhjpr5ne7fl92lqki7h
    private static final String SECRET = "hipouhb455s5"; //21f9us7smltjr
    private static final String ACCEPT_ENCODING = "gzip";
    private static final String USER_AGENT = "TravelNow/3.30.112";
    private static final String EXPEDIA_REQUEST_LOCAL_CN = "zh-CN";
    private static final String EXPEDIA_REQUEST_LOCAL_EN = "en-US";
    private static final int EXPEDIA_REQUEST_TIMEOUT = 5000;
    private static final String PAGE_NAME = "Link";

    private volatile boolean isPauseGetHotelInfo = false;

    @Override
    public HotelInfoResponse getHotelInfoCN(String hotelCode, Map<String, String> options, String netPageUrl) {
        return getHotelInfo(hotelCode, EXPEDIA_REQUEST_LOCAL_CN, options, 0, netPageUrl);
    }

    @Override
    public HotelInfoResponse getHotelInfoEN(String hotelCode, Map<String, String> options, String netPageUrl) {
        return getHotelInfo(hotelCode, EXPEDIA_REQUEST_LOCAL_EN, options, 0, netPageUrl);
    }

    /**
     * 拉取酒店信息
     *
     * @param hotelCode
     * @param local     语言参数 中文zh_CN， 英文 en_US
     * @return
     */
    private HotelInfoResponse getHotelInfo(String hotelCode, String local, Map<String, String> options, int times, String netPageUrl) {
        // 重试次数为0，则结束递归
        if (times < 0) {
            logger.error("【getHotelInfo】查询Expedia酒店信息重试次数已满, hotelCode:{}", hotelCode);
            return null;
        }
        times--;

//        while (this.isPauseGetHotelInfo) {
//            try {
//                Thread.sleep(Constant.TIME_SECOND);
//            } catch (InterruptedException e) {
//                logger.warn("Interrupted!", e);
//                Thread.currentThread().interrupt();
//            }
//        }

        logger.info("【getHotelInfo】调用expedia接口开始, hotelCode:{}, times:{}", hotelCode, times);

        HttpResponseInfo response = null;
        String url = buildRequestHotelUrl(hotelCode, local, options, netPageUrl);
//        System.out.println(url);
        try {
            response = HttpClientUtil.getWithTimeout(url, 5000, getHotelHeader());
//            if (!StringUtils.isEmpty(netPageUrl)) {
//                response = HttpClientUtil.getWithTimeout(url, 5000, getHotelHeader());
//            } else {
//                response = HttpClientUtil.getWithTimeout(url, 5000, getHotelHeader());
//            }
        } catch (Exception e) {
            logger.error("接口调用错误, url:{}, message:{}", url, e.getMessage());
        }
        //返回不成功则重试
        if (null == response || response.getCode() != HttpStatus.SC_OK) {
            return getHotelInfo(hotelCode, local, options, times, netPageUrl);
        }
        HotelInfoResponse hotelInfoResponse = handlerContentResponse(response);
//        if (hotelInfoResponse == null || hotelInfoResponse.getHotelInformationResponse() == null || !StringUtils.isEmpty(hotelInfoResponse.getType())) {
//            if (!this.isPauseGetHotelInfo) {
//                this.isPauseGetHotelInfo = true;
//                logger.error("请求Expedia酒店信息异常 hotelInfoResponse:{}", JSONObject.toJSONString(hotelInfoResponse));
//                try {
//                    Thread.sleep(Constant.TIME_TEN_SECOND);
//                } catch (InterruptedException e) {
//                    logger.warn("Interrupted!", e);
//                    Thread.currentThread().interrupt();
//                }
//                logger.info("查询Expedia酒店静态信息暂停恢复！！！");
//                this.isPauseGetHotelInfo = false;
//            }
//            return getHotelInfo(hotelCode, local, options, times, netPageUrl);
//        }

        logger.info("【getHotelInfo】调用expedia接口结束, hotel_code:{}", hotelCode);
        return hotelInfoResponse;
    }

    /**
     * 拼接region request请求
     * @param netPageUrl
     * @return
     */
    private String buildRequestHotelUrl(String hotelCode, String locale, Map<String, String> option, String netPageUrl) {
        if (!StringUtils.isEmpty(netPageUrl)) {
            return netPageUrl.substring(1, netPageUrl.indexOf(";")-1);
        }
        StringBuffer url = new StringBuffer();
        url.append(EXPEDIA_HOTEL_URL + "?language=" + locale);
        if (!StringUtils.isEmpty(hotelCode)) {
            url.append("&property_id=" + hotelCode);
        }
        if (option != null && option.size() > 0) {
            for (Map.Entry<String, String> entry : option.entrySet()) {
                url.append("&" + entry.getKey() + "=" + entry.getValue());
            }
        }
        return url.toString();
    }

    /**
     * 生成header
     * @return
     */
    private Map<String, String> getHotelHeader() {
        Map<String, String> header = new HashMap<>(10);
        header.put("Accept", "application/json");
        header.put("Accept-Encoding", ACCEPT_ENCODING);
        header.put("Authorization", setSig());
        header.put("User-Agent", USER_AGENT);
        return header;
    }

    /**
     * 生成sig授权用
     *
     * @return
     */
    private String setSig() {
        String authorization = null;
        try {
            authorization = ExpediaSignatureUtil.calculationSignature(API_KEY, SECRET);
        } catch (Exception e) {
            logger.error("生成expedia签名错误", e);
        }
        return authorization;
    }


    /**
     * 拼接region request请求
     * @param netPageUrl
     * @return
     */
    private String buildAllRegionRequestUrl(String netPageUrl, String locale, String include, Map<String, String> option) {
        if (!StringUtils.isEmpty(netPageUrl)) {
            return netPageUrl.substring(1, netPageUrl.indexOf(";")-1);
        }
        StringBuffer url = new StringBuffer();
        url.append(EXPEDIA_REGION_URL + "?language=" + locale + "&include=" + include);
        if (option != null && option.size() > 0) {
            for (Map.Entry<String, String> entry : option.entrySet()) {
                url.append("&" + entry.getKey() + "=" + entry.getValue());
            }
        }
        return url.toString();
    }


    @Override
    public RegionInfoResponse getHotelOfRegion(String netPageUrl, String locale, String include, Map<String, String> option) {
        logger.info("【getHotelOfRegion】调用expedia接口开始, page_erl:{}", netPageUrl);
        int times = 5;
//        String responseStr = "";
        HttpResponseInfo response = null;
        while (times > 0) {
            String url = buildAllRegionRequestUrl(netPageUrl, locale, include, option);
            try {
                response = HttpClientUtil.getWithTimeout(url, 5000, getHotelHeader());
//                if (!StringUtils.isEmpty(netPageUrl)) {
//                    response = HttpClientUtil.getWithTimeout(url, 5000, getHotelHeader());
//                } else {
//                    response = HttpClientUtil.getWithTimeout(url, 5000, getHotelHeader());
//                }
                break; //请求成功则跳过
            } catch (Exception e) {
                logger.error("接口调用错误, url:{}, message:{}", url, e.getMessage());
                times--;
            }
        }
        logger.info("【getRoomImagesInfo】调用expedia接口结束, page_erl:{}", netPageUrl);
        RegionInfoResponse regionInfoResponse = handlerRegionResponse(response);
        return regionInfoResponse;
    }

    /**
     * 解析region接口response
     * @param response
     * @return
     */
    private RegionInfoResponse handlerRegionResponse(HttpResponseInfo response) {
        RegionInfoResponse regionInfoResponse = null;
        if (null != response) {
            int code = response.getCode();
            //判断请求是否成功
            if (code == HttpStatus.SC_OK) { //请求成功时但会的是regionInfoMap对象
                regionInfoResponse = new RegionInfoResponse();
                Map<String, RegionInfo> regionInfoMap =  JSONObject.parseObject(response.getResponseStr(), Map.class);
                regionInfoResponse.setRegionInfo(regionInfoMap);
            } else { //请求不成功时返回的是错误信息，可直接转为RegionInfoResponse对象
                regionInfoResponse = JSONObject.parseObject(response.getResponseStr(), RegionInfoResponse.class);
            }
            if (response.getHeaders().length > 0) {
                for (Header item : response.getHeaders()) {
                    if (PAGE_NAME.equals(item.getName())) { //如有下一页，则取得下一页
                        regionInfoResponse.setLink(item.getValue());
                        break;
                    }
                }
            }
        }
        return regionInfoResponse;
    }

    /**
     * 解析content接口response
     * @param response
     * @return
     */
    private HotelInfoResponse handlerContentResponse(HttpResponseInfo response) {
        HotelInfoResponse hotelInfoResponse = null;
        if (null != response) {
            int code = response.getCode();
            //判断请求是否成功
            if (code == HttpStatus.SC_OK) { //请求成功时但会的是regionInfoMap对象
                hotelInfoResponse = new HotelInfoResponse();
                Map<String, HotelInformationResponseExpedia> regionInfoMap =  JSON.parseObject(response.getResponseStr(),
                        new TypeReference<HashMap<String, HotelInformationResponseExpedia>>() {});
                hotelInfoResponse.setHotelInformationResponse(regionInfoMap);
            } else { //请求不成功时返回的是错误信息，可直接转为RegionInfoResponse对象
                hotelInfoResponse = JSONObject.parseObject(response.getResponseStr(), HotelInfoResponse.class);
            }
            if (response.getHeaders().length > 0) {
                for (Header item : response.getHeaders()) {
                    if (PAGE_NAME.equals(item.getName())) { //如有下一页，则取得下一页
                        hotelInfoResponse.setLink(item.getValue());
                        break;
                    }
                }
            }
        }
        return hotelInfoResponse;
    }

    @Override
    public ChainInfoResponse getChain(Map<String, String> option) {
        logger.info("【getChain】调用chain接口开始");
        int times = 5;
        HttpResponseInfo response = null;
        while (times > 0) {
            String url = buildChainRequestUrl(option);
            try {
                response = HttpClientUtil.getWithTimeout(url, 5000, getHotelHeader());
                break; //请求成功则跳过
            } catch (Exception e) {
                logger.error("接口调用错误, url:{}, message:{}", url, e.getMessage());
                times--;
            }
        }
        logger.info("【getChain】调用chain接口开始");
        ChainInfoResponse chainInfoResponse = handlerChainResponse(response);
        return chainInfoResponse;
    }

    /**
     * 解析返回的chainInfo
     * @param response
     * @return
     */
    private ChainInfoResponse handlerChainResponse(HttpResponseInfo response) {
        ChainInfoResponse chainInfoResponse = null;
        if (null != response) {
            int code = response.getCode();
            //判断请求是否成功
            if (code == HttpStatus.SC_OK) { //请求成功时但会的是regionInfoMap对象
                chainInfoResponse = new ChainInfoResponse();
                Map<String, HotelChain> chainInfoMap =  JSONObject.parseObject(response.getResponseStr(), Map.class);
                chainInfoResponse.setChainInfo(chainInfoMap);
            } else { //请求不成功时返回的是错误信息，可直接转为RegionInfoResponse对象
                chainInfoResponse = JSONObject.parseObject(response.getResponseStr(), ChainInfoResponse.class);
            }
        }
        return chainInfoResponse;
    }

    /**
     * 构建连锁品牌请求url
     * @param option 可选参数
     * @return
     */
    private String buildChainRequestUrl(Map<String, String> option) {
        StringBuffer url = new StringBuffer(EXPEDIA_CHAIN_URL);
        if (option != null && option.size() > 0) {
            for (Map.Entry<String, String> entry : option.entrySet()) {
                url.append("&" + entry.getKey() + "=" + entry.getValue());
            }
        }
        return url.toString();
    }

    public static void main(String[] args) {
        ExpediaHttpServiceImpl e = new ExpediaHttpServiceImpl();
        System.out.println(e.setSig());
    }

}
